<?php

class Model_User extends Model_Dec {
	
	const TABLE = "user";

	/**
	 * @var protected $id id value
	 * @method int get_id() get_id(void)
	 * @method void set_id() set_id(int $id)
	 */
	protected $id = 0;

	/**
	 * @var protected $name name value
	 * @method string get_name() get_name(void)
	 * @method void set_name() set_name(string $name) 
	 */
	protected $name;

	/**
	 * @var protected $email email value
	 * @method string get_email() get_email(void)
	 * @method void set_email() set_email(string $email) 
	 */
	protected $email;

	/**
	 * @var protected $password password value
	 * @method string get_password() get_password(void)
	 * @method void set_password() set_password(string $password) 
	 */
	protected $password;

	/**
	 * @var protected $logins logins value
	 * @method int get_logins() get_logins(void)
	 * @method void set_logins() set_logins(int $logins) 
	 */
	protected $logins = 0;

	/**
	 * @var protected $last_login last_login value
	 * @method string get_last_login() get_last_login(void)
	 * @method void set_last_login() set_last_login(string $last_login) 
	 */
	protected $last_login;

	/**
	 * @return Model_User
	 */
	public function __construct($id=0) {
		if(is_numeric($id)) {
			$db = DB::select("id", "name", "email", "password", "logins", "last_login")->from(self::TABLE)->where("id", "=", $id)->limit(1);
		} else {
			$db = DB::select("id", "name", "email", "password", "logins", "last_login")->from(self::TABLE)->where("email", "=", $id)->limit(1);
		}
		$db = $db->as_assoc()->execute();
		if($db->count()>0) {
			$this->load($db->current());
		}
	}

	public static function get_all($limit = false) {
		$db = DB::select("id", "name", "email", "password", "logins", "last_login")->from(self::TABLE)->as_object(__CLASS__);
		if ($limit)
			$db->limit($limit);
		$result = $db->execute();
		
		$return = array();
		foreach($result as $obj){
			$return[] = $obj;
		}
		return $return;
	}

	private static function get_database_fields() {
		return array(
			'name' => __("User_Name"),
			'email' => __("User_Email"),
			'password' => __("User_Password"),
			'logins' => __("User_Logins"),
			'last_login' => __("User_LastLogin"),
		);
	}

	public function validate() {
		$validateArray = array();
		foreach (self::get_database_fields() as $key => $value) {
			$validateArray[$key] = $this->get($key);
		}
		$validation = Validation::factory($validateArray)
				->rule('name', 'not_empty')
				->rule('name', 'max_length', array(':value', 32))
				->rule('email', 'not_empty')
				->rule('email', 'email')
				->rule('password', 'not_empty')
				->rule('password', 'min_length', array(':value', 4));
		if ($validation->check()) {
			return $validateArray;
		} else {
			throw new Validation_Exception('validation', $validation);
		}
	}
	
	public static function get_report() {
		return DB::select(
				"id"
				, "email"
				, "name"
				, "password"
				, "logins"
				, "last_login"
				, array("id", "actions"))
		->from(self::TABLE)
		->order_by("id", "ASC");
	}

	public static function confirm_password($password, $confirm) {
		$validation = Validation::factory(array('password' => $password, 'confirm' => $confirm))
				->rule('password', 'not_empty')
				->rule('password', 'min_length', array(':value', 4))
				->rule('confirm', 'matches', array(':validation', 'password', ':field'));
		if ($validation->check()) {
			return true;
		} else {
			throw new Validation_Exception('confirm password', $validation);
		}
	}

	public static function unique_email($email) {
		$validation = Validation::factory(array('email' => $email))
				->rule('email', 'Model_User::unique', array(':value', 'email'));
		if ($validation->check()) {
			return true;
		} else {
			throw new Validation_Exception('verify unique', $validation);
		}
	}

	/**
	 * @method void add_role(mixed $role) add role or roles (if array) to the user 
	 */
	public function add_role($role) {
		if (is_array($role) || ($role instanceof Database_MySQL_Result)) {
			foreach ($role as $role_item) {
				if(is_numeric($role_item)) {
					$role_item = Model_Role::factory($role_item);
				}
				$this->add_role($role_item->get_name());
			}
		} else {
			if (!$this->has_role($role)) {
				$role = Model_Role::factory($role);
				DB::insert('role_user', array('user_id', 'role_id'))->values(array($this->id, $role->get_id()))->execute();
			}
		}
	}

	public function has_role($role) {
		$role = Model_Role::factory($role);
		$role_user = DB::select()->from('role_user')
						->where('user_id', '=', $this->id)
						->and_where('role_id', '=', $role->get_id())
						->limit(1)->execute()->current();
		return $role_user ? true : false;
	}

	/**
	 * @method void remove_role(mixed $role) remove role or roles (if array) to the user 
	 */	
	public function remove_role($role) {
		if(is_array($role) || ($role instanceof Database_MySQL_Result)) {
			foreach ($role as $role_item) {
				if(is_numeric($role_item)) {
					$role_item = Model_Role::factory($role_item);
				}
				$this->remove_role($role_item->get_name());
			}
		} else {
			if ($this->has_role($role)) {
				$role = Model_Role::factory($role);
				DB::delete('role_user')->where('user_id', '=', $this->get_id())->and_where('role_id', '=', $role->get_id())->execute();
			}
		}
	}

	public function get_roles() {
		return DB::select()->from('role')
						->join('role_user')->on('role.id', '=', 'role_user.role_id')
						->where('role_user.user_id', '=', $this->get_id())
						->as_object("Model_Role")->execute();
	}
	
	public function get_roles_as_array() {
		$roles = array();
		foreach($this->get_roles() as $role){
			$roles[$role->get_id()] = $role->get_name();
		}
		return $roles;
	}

	public function remove() {
		$this->remove_role($this->get_roles());
		parent::remove();
	}

	public static function unique($value, $field) {
		$sql = DB::select()->from("user")->where($field, "=", $value);
		$return = $sql->execute();
		if ($return->count() > 0) {
			return false;
		} else {
			return true;
		}
	}

	public static function hash($str) {
		if (!Kohana::$config->load('dec')->hash_key) {
			throw new Kohana_Exception(__('A valid hash key must be set in your auth config.'));
		}
		return hash_hmac(Kohana::$config->load('dec')->hash_method, $str, Kohana::$config->load('dec')->hash_key);
	}
	
	public static function logged_in($role=null) {
		$user = self::get_user();
		if (!$user) {
			return false;
		}
		if ($user instanceof Model_User) {
			if (!$role) {
				return true;
			}
			if (!is_object($role)) {
				$role = DB::select()->from("role")
						->where("name", "=", $role)
						->as_object()->execute()->current();
				if(!$role) {
					return false;
				}
			}
			return $user->has_role($role->name);
		}
		return false;
	}	
	
	public static function login($user, $password) {
		if (!empty($user) || !empty($password)) {
			if (!is_object($user)) {
				$user = Model_User::factory($user);
			}
			if (is_string($password)) {
				$password = Model_User::hash($password);
			}
			if ($user->has_role("login") && $user->get_password() === $password) {
				$user->set_logins($user->get_logins() + 1);
				$user->set_last_login(date("Y-m-d H:i:s"));
				$user->save();
				$session = Session::instance(Session::$default);
				$session->regenerate();
				$session->set('user', $user);
				return true;
			}
		}
		return false;
	}

	public static function get_user() {
		$session = Session::instance(Session::$default);
		return $session->get('user');
	}	
	
	public static function logout() {
		$session = Session::instance(Session::$default);
		$session->delete('user');
		$session->regenerate();
		return!self::logged_in();
	}
        public function get_last_modification(){
            $last_modification = DB::select("last_modification")->from("user_actions")->where("user_id","=", $this->id)->as_object()->execute()->current();
            if(!empty($last_modification))
                return $last_modification->last_modification;
            else{
                DB::insert("user_actions", array("user_id"))->values(array($this->id))->execute();
                return DB::select("last_modification")->from("user_actions")->where("user_id","=", $this->id)->as_object()->execute()->current()->last_modification;
            }
        }
        public function set_last_modification(){
            DB::update("user_actions")
                    ->set(array("last_modification"=>DB::expr("NOW()")))
                    ->where("user_id","=",$this->id)->execute();
        }
        public function get_last_generation(){
            $last_generation = DB::select("last_generation")->from("user_actions")->where("user_id","=", $this->id)->as_object()->execute()->current();
            if(!empty($last_generation))
                return $last_generation->last_generation;
            else{
                DB::insert("user_actions", array("user_id"))->values(array($this->id))->execute();
                return DB::select("last_generation")->from("user_actions")->where("user_id","=", $this->id)->as_object()->execute()->current()->last_generation;
            }
        }
        public function set_last_generation(){
            DB::update("user_actions")
                    ->set(array("last_generation"=>DB::expr("NOW()")))
                    ->where("user_id","=",$this->id)->execute();
        }

} // End User